/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package rtp_manager;

import java.io.*;
import java.net.*;
import java.util.*;

import org.jitsi.service.libjitsi.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.device.*;
import org.jitsi.service.neomedia.format.*;

/**
 *
 * @author cuongmv
 */
public class MediaTransceive {

    private int             localPortBase;
    
    private MediaStream[]   mediaStreams;
    
    private InetAddress     remoteAddr;
    
    private int             remotePortBase;
    
    public MediaTransceive(String localPortBase, String remoteHost, String remotePortBase) throws Exception
    {
        this.localPortBase = (localPortBase == null) ? -1 : Integer.valueOf(localPortBase).intValue();
        
        this.remoteAddr = InetAddress.getByName(remoteHost);
        
        this.remotePortBase = Integer.valueOf(remotePortBase).intValue();
    }
    
    public MediaTransceive()
    {
        
    }

    public int getLocalPortBase() {
        return localPortBase;
    }

    public void setLocalPortBase(int localPortBase) {
        this.localPortBase = localPortBase;
    }

    public InetAddress getRemoteAddr() {
        return remoteAddr;
    }

    public void setRemoteAddr(InetAddress remoteAddr) {
        this.remoteAddr = remoteAddr;
    }

    public int getRemotePortBase() {
        return remotePortBase;
    }

    public void setRemotePortBase(int remotePortBase) {
        this.remotePortBase = remotePortBase;
    }
         
    private boolean initialize() throws Exception
    {
        LibJitsi.start();
         
        MediaType[] mediaTypes = MediaType.values();

        MediaService mediaService = LibJitsi.getMediaService();
        int localPort = localPortBase;
        int remotePort = remotePortBase;
        
        mediaStreams = new MediaStream[mediaTypes.length];
        
        for (MediaType mediaType : mediaTypes)
        {
            MediaDevice device = mediaService.getDefaultDevice(mediaType, MediaUseCase.CALL);
            
            MediaStream mediaStream = mediaService.createMediaStream(device);
                        
            // Set direction for media transmissions:
            mediaStream.setDirection(MediaDirection.SENDRECV);
            
            // Set format for media
            String encoding;            
            double clockRate;
            byte dynamicRTPPayloadType;
            
            switch (device.getMediaType())
            {
            case AUDIO:
                encoding = "PCMU";
                clockRate = 8000;
                dynamicRTPPayloadType = -1;
                break;
            case VIDEO:  // Not in use for this app
                encoding = "H264";
                clockRate = MediaFormatFactory.CLOCK_RATE_NOT_SPECIFIED;
                dynamicRTPPayloadType = 99;
                break;
            default:
                encoding = null;
                clockRate = MediaFormatFactory.CLOCK_RATE_NOT_SPECIFIED;
                dynamicRTPPayloadType = -1;
            }
            
            if (encoding != null)
            {
                MediaFormat format = mediaService.getFormatFactory().createMediaFormat(encoding, clockRate);
                
                if (dynamicRTPPayloadType != -1)
                {
                    mediaStream.addDynamicRTPPayloadType(dynamicRTPPayloadType, format);
                }
                
                mediaStream.setFormat(format);
            }
            
            // Connector: Media Connection
            StreamConnector connector;
            
            if(localPortBase == -1)
            {
                connector = new DefaultStreamConnector();
            }
            else 
            {
                int localRTPPort = localPort++;
                int localRTCPPort = localPort++;
                
                connector = new DefaultStreamConnector(new DatagramSocket(localRTPPort), new DatagramSocket(localRTCPPort));
            }
            
            mediaStream.setConnector(connector);
            
            // Target
            int remoteRTPPort = remotePort++;
            int remoteRTCPPort = remotePort++;

            mediaStream.setTarget(
                        new MediaStreamTarget(
                                new InetSocketAddress(remoteAddr, remoteRTPPort),
                                new InetSocketAddress(remoteAddr, remoteRTCPPort)));
            
            // Set Stream name, so that it may be integrated with the signaling functionality:
            mediaStream.setName(mediaType.toString());
            mediaStreams[mediaType.ordinal()] = mediaStream;
        }
        
        // Starting:
        
        for (MediaStream mediaStream : mediaStreams)
        {
            if (mediaStream != null && mediaStream.getName().equals("audio")) //Start audio only
            {
                mediaStream.start();
            }
        }
        
        return true;
    }
    
    public boolean startMediaTransmission() throws Exception
    {
       
        return initialize();
    }
    
    public boolean startMediaTransmission(String localPortBase, String remoteHost, String remotePortBase) throws Exception
    {
        this.localPortBase = (localPortBase == null) ? -1 : Integer.valueOf(localPortBase).intValue();
        
        this.remoteAddr = InetAddress.getByName(remoteHost);
        
        this.remotePortBase = Integer.valueOf(remotePortBase).intValue();
        
        return initialize();
    }
    
    public boolean stopMediaTransmission() throws Exception
    {

        close();
        
        LibJitsi.stop(); 
        
        return true;
    }
    
    private void close()
    {
        if (mediaStreams != null)
        {
            for (int i = 0; i < mediaStreams.length; i++)
            {
                MediaStream mediaStream = mediaStreams[i];

                if (mediaStream != null)
                {
                    try
                    {
                        mediaStream.stop();
                    }
                    finally
                    {
                        mediaStream.close();
                        mediaStreams[i] = null;
                    }
                }
            }

            mediaStreams = null;
        }
    }
    
    public static void main(String[] args) throws Exception {
        // TODO code application logic here
        MediaTransceive mediaTransceive = new MediaTransceive("5678", "192.168.10.86", "5678");
        
        mediaTransceive.startMediaTransmission();
        
    } 
}
